package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"sort"
	"strings"
	"time"

	"goscan/arp"
	"goscan/dns"
	"goscan/global"
	"goscan/ip"
	"goscan/manuf"
)

// 格式化输出结果
// xxx.xxx.xxx.xxx  xx:xx:xx:xx:xx:xx  hostname  manuf
// xxx.xxx.xxx.xxx  xx:xx:xx:xx:xx:xx  hostname  manuf
func PrintData() {
	var keys ip.IPSlice
	for k := range global.Data {
		keys = append(keys, ip.ParseIPString(k))
	}
	sort.Sort(keys)
	for _, k := range keys {
		d := global.Data[k.String()]
		mac := ""
		if d.Mac != nil {
			mac = d.Mac.String()
		}
		fmt.Printf("%-15s %-17s %-30s %-10s\n", k.String(), mac, d.Hostname, d.Manuf)
	}
}

func setupNetInfo(f string) {
	var ifs []net.Interface
	var err error
	if f == "" {
		ifs, err = net.Interfaces()
	} else {
		// 已经选择iface
		var it *net.Interface
		it, err = net.InterfaceByName(f)
		if err == nil {
			ifs = append(ifs, *it)
		}
	}
	if err != nil {
		log.Fatal("无法获取本地网络信息:", err)
	}
	for _, it := range ifs {
		addr, _ := it.Addrs()
		for _, a := range addr {
			if ip, ok := a.(*net.IPNet); ok && !ip.IP.IsLoopback() {
				if ip.IP.To4() != nil {
					global.IpNet = ip
					global.LocalHaddr = it.HardwareAddr
					global.Iface = it.Name
					goto END
				}
			}
		}
	}
END:
	if global.IpNet == nil || len(global.LocalHaddr) == 0 {
		log.Fatal("无法获取本地网络信息")
	}
}

func localHost() {
	host, _ := os.Hostname()
	global.Data[global.IpNet.IP.String()] = global.Info{Mac: global.LocalHaddr, Hostname: strings.TrimSuffix(host, ".local"), Manuf: manuf.Search(global.LocalHaddr.String())}
}

func sendARP() {
	// ips 是内网IP地址集合
	ips := ip.Table(global.IpNet)
	for _, ip := range ips {
		go arp.SendArpPackage(ip)
	}
}

func main() {
	// allow non root user to execute by compare with euid
	// if os.Geteuid() != 0 {
	// 	log.Fatal("goscan must run as root.")
	// }
	flag.StringVar(&global.Iface, "I", "", "Network interface name")
	flag.Parse()
	// 初始化 data
	global.Data = make(map[string]global.Info)
	global.Do = make(chan string)
	// 初始化 网络信息
	setupNetInfo(global.Iface)

	ctx, cancel := context.WithCancel(context.Background())
	go arp.ListenARP(ctx)
	go dns.ListenMDNS(ctx)
	go dns.ListenNBNS(ctx)
	go sendARP()
	go localHost()

	t := time.NewTicker(4 * time.Second)
	for {
		select {
		case <-t.C:
			PrintData()
			cancel()
			goto END
		case d := <-global.Do:
			switch d {
			case global.START:
				t.Stop()
			case global.END:
				// 接收到新数据，重置2秒的计数器
				t = time.NewTicker(2 * time.Second)
			}
		}
	}
END:
}
